<?php

/**
 * @Name  融云IM
 * @Description 融云IM封装工具类
 */

namespace App\Helpers;

use App\Model\User;
use Exception;

use function GuzzleHttp\json_encode;

class ImUtil
{
    //融云消息类型
    const RONG_TEXT_TYPE = 'RC:TxtMsg';
    const RONG_IMG_TYPE = 'RC:ImgMsg';
    const RONG_SOUND_TYPE = 'RC:VcMsg';
    const RONG_CMD_TYPE = 'RC:CmdMsg';
    const RONG_HQ_SOUND_TYPE = 'RC:HQVCMsg';
    const RONG_READ_NTF = 'RC:ReadNtf';
    //小灰条提示
    const RONG_INFO_TIP = 'RC:InfoNtf';
    //自定义图片
    const RONG_IMG_NEW = 'JT:USER_IMAGE';

    //自定义系统(官方通知)消息
    const MSG_TYPE_SYSMSG = 'VC:SYS_MSG';
    //自定义纯推送消息
    const MSG_TYPE_PUSHMSG = 'VC:PUSH_MSG';

    //自定义消息 - 礼物
    const MSG_TYPE_GIFT = 'VC:GIFT_MSG';
    //自定义消息 - 礼物收到
    const MSG_TYPE_GIFT_RECEIVE = 'VC:GIFT_MSG_RECEIVE';
    //自定义消息 - 系统提示
    const MSG_SYS_TIP = 'VC:SYS_TIP_MSG';
    //自定义消息 - 资料名片
    const MSG_TYPE_PROFILE_CARD = 'VC:PROFILE_CARD';
    //自定义消息 - 亲密值提醒
    const MSG_TYPE_CLOSE_TIP = 'VC:CLOSE_TIP';
    //自定义消息 - 认证系统提醒
    const MSG_TYPE_VERYFY_OK = 'VC:VERYFY_OK_TIP';
    //自定义消息 - 金币不足
    const MSG_TYPE_COIN_NOT_ENOUGH = 'VC:COIN_NOT_ENOUGH_TIP';
    //自定义消息 - 消息违规
    const MSG_BREAK_THE_RULE = 'VC:BREAK_THE_RULE';

    //路由的消息类型
    const ROUTE_MSG_TYPE = [
        self::RONG_TEXT_TYPE, self::RONG_IMG_TYPE, self::RONG_SOUND_TYPE, self::RONG_HQ_SOUND_TYPE, self::RONG_IMG_NEW
    ];

    //系统提示消息类型
    const SYS_MSG_TYPE = [
        1 => '普通系统提示',
        2 => '私信收费提示',
    ];

    //单聊 - 单次批量发送消息最大数
    const SINGLE_MAX_NUM = 999;
    //用户标签查询 - 单次批量最大数
    const TAG_GET_MAX_NUM = 50;
    //用户标签设置 - 单次批量最大数
    const TAG_SET_MAX_NUM = 1000;

    /**
     * 创建IM账号
     * @param string $username
     * @param string $nickname
     * @return mixed|null
     */
    public function createUser($username = '', $nickname = '', $avatar = '')
    {
        $ret = (new RongCloud())->getToken($username, $nickname, $avatar);
        return $ret;
    }

    /**
     * 单发单聊消息-文本
     * @param string $receiver
     * @param string $text_content
     * @param string $sender
     * @return array|mixed|string
     */
    static function sendTextMsg($receiver = '', $textContent = '', $sender = '', $syncOtherMachine = -1)
    {
        if (!$receiver || !$sender) return false;
        $msgType = self::RONG_TEXT_TYPE;
        $content = [
            'content' => $textContent,
            'extra' => '',
            'is_system' => 1
            // 'user' => [
            //     'id' => $sender,
            //     'name' => '官方消息',
            //     'portrait' => ConfigUtil::getSystemIcon(),
            //
        ];
        $isIncludeSender = $syncOtherMachine == 2 ? 0 : 1;
        if (!is_array($receiver)) $receiver = [$receiver];
        else $receiver = array_values($receiver);
        $ret = (new RongCloud())->messagePrivatePublish($sender, $receiver, $msgType, json_encode($content), $isIncludeSender);
        log_info(__CLASS__ . "==sendTextMsg==" . json_encode([$sender, $receiver]) . "==" . json_encode($ret));
        return $ret;
    }

    /**
     * 单发单聊消息 - 图片
     * @param string $receiver
     * @param string $imagePath
     * @param string $sender
     * @return array|mixed|string
     */
    static function sendImageMsg($receiver = '', $imagePath = '', $sender = '', $isIncludeSender = 1)
    {
        if (!$receiver || !$sender) return false;
        $msgType = self::RONG_IMG_NEW;
        $imgUrl = strpos($imagePath, 'http') === false ? AliyunUtil::IMG_HOST . $imagePath : $imagePath;
        // $imgStr = !file_exists($imgUrl) ? '' : str_replace(["\r\n", "\r", "\n"], "", base64_encode(file_get_contents($imgUrl)));
        $content = [
            'msg_type' => 0,
            'ext_info' => [
                'width' => 250,
                'height' => 400,
                "image" => $imgUrl,
                'thumbnail' => $imgUrl,
            ],
            'is_system' => 1
        ];
        $ret = (new RongCloud())->messagePrivatePublish($sender, $receiver, $msgType, json_encode($content), $isIncludeSender);
        log_info(__CLASS__ . "==sendImageMsg==" . json_encode([$sender, $receiver, $imagePath]) . '==' . json_encode($ret));
        return $ret;
    }

    /**
     * 单发单聊消息 - 语音
     * @param string $receiver
     * @param string $voice_path
     * @param string $sender
     * @return array|mixed|string
     */
    static function sendVoiceMsg($receiver = '', $sender = '', $voicePath = '', $voiceDuration = 1, $isIncludeSender = 1)
    {
        if (!$receiver || !$sender) return false;
        $msgType = self::RONG_HQ_SOUND_TYPE;
        
        $voiceUrl = strpos($voicePath, 'http') === false ? AliyunUtil::VOICE_HOST . $voicePath : $voicePath;
        $content = [
            'localPath' => '',
            'remoteUrl' => $voiceUrl,
            "duration" => $voiceDuration,
            'extra' => '',
            'is_system' => 1
        ];
        $ret = (new RongCloud())->messagePrivatePublish($sender, $receiver, $msgType, json_encode($content), $isIncludeSender);
        log_info(__CLASS__ . "==sendVoiceMsg==" . json_encode([$sender, $receiver, $voicePath]) . '==' . json_encode($ret));
        return $ret;
    }

    /**
     * 发送系统提示信息
     */
    static function sendInfoTipMsg($receiver = '', $textContent = '', $sender = '', $tipType = 1)
    {
        $msgType = self::MSG_SYS_TIP;
        $content = json_encode([
            'sys_tip' => $textContent,
            'sys_msg_type' => $tipType
        ]);
        if (!is_array($receiver)) $receiver = [$receiver];
        else $receiver = array_values($receiver);
        $ret = (new RongCloud())->messagePrivatePublish($sender, $receiver, $msgType, $content, 0);
        log_info(__CLASS__ . "=={$msgType}==" . json_encode([$sender, $receiver]) . "=={$content}");
        return $ret;
    }

    /**
     * 纯push推送
     * @return mixed
     */
    static function sendPushMsg($receivers = [], $content = [], $pushContent = '')
    {
        $receivers = !is_array($receivers) ? [$receivers] : array_values($receivers);
        $accountArr = array_chunk($receivers, self::SINGLE_MAX_NUM);
        $ret = 0;
        $rongcloud = new RongCloud();
        $content = json_encode($content);
        $sender = config('busi.officialImAccount');
        $isIncludeSender = $isCounted = $isPersisted = 0;
        foreach ($accountArr as $round => $accounts) {
            // try {
            //     $audience['is_to_all'] = false;
            //     $audience['userid'] = $accounts;
            //     $notification['android']['title'] = '新消息来咯！';
            //     $notification['alert'] = $notification['android']['alert'] = $pushContent;
            //     $ret = $rongcloud->push(['android'], $audience, $notification);
            //     log_info(__METHOD__ . "==Count:" . count($accounts) . "==PushContent:{$pushContent}==Round:{$round}==Ret:{$ret}");
            // } catch (Exception $e) {
            //     log_info(__METHOD__ . "==Exception:" . $e->getMessage());
            //     continue;
            // }
            try {
                $ret = $rongcloud->messagePrivatePublish(
                    $sender,
                    $accounts,
                    self::MSG_TYPE_PUSHMSG,
                    $content,
                    $isIncludeSender,   //暂不存储发送方
                    $isCounted, //不显示未读消息
                    $isPersisted,   //融云服务端不存储
                    $pushContent,  //显示的 Push 内容
                    $content  //Android客户端收到推送消息字段
                );
                log_info(__METHOD__ . "==Count:" . count($accounts) . "==PushContent:{$pushContent}==Round:{$round}==Ret:{$ret}");
            } catch (Exception $e) {
                log_info(__METHOD__ . "==Exception:" . $e->getMessage());
                continue;
            }
        }
        return $ret;
    }

    /**
     * 纯push推送-通过标签
     * @return mixed
     */
    static function sendPushMsgByTag($tags = [], $pushContent = '')
    {
        $rongcloud = new RongCloud();
        $ret = 0;
        try {
            $audience['is_to_all'] = false;
            $audience['tag'] = $tags;
            $notification['android']['title'] = '新消息来咯！';
            $notification['alert'] = $notification['android']['alert'] = $pushContent;
            $ret = $rongcloud->push(['android'], $audience, $notification);
            log_info(__METHOD__ . "==PushContent:{$pushContent}==Tags:" . json_encode($tags) . "==Ret:{$ret}");
        } catch (Exception $e) {
            log_info(__METHOD__ . "==Exception:" . $e->getMessage());
        }
        return $ret;
    }

    /**
     * 单发单聊消息-自定义
     * @param string $receiver
     * @param array $content
     * @param string $sender
     * @return array|mixed|string
     */
    static function sendCustomMsg(
        $receiver = '',
        $sender = '',
        $msgType = self::MSG_TYPE_GIFT,
        $content = [],
        $pushContent = '',
        $isIncludeSender = 1,
        $isPersisted = 1,
        $isCounted = 1
    ) {
        if (!$sender || !$receiver) return false;
        $content = json_encode($content);
        // $isIncludeSender = 1;
        if (!is_array($receiver)) $receiver = [$receiver];
        else $receiver = array_values($receiver);
        $ret = (new RongCloud())->messagePrivatePublish($sender, $receiver, $msgType, $content, $isIncludeSender, $isCounted, $isPersisted, $pushContent);
        log_info(__CLASS__ . "==sendCustomMsg==" . json_encode($receiver) . "=={$sender}=={$msgType}=={$content}");
        return $ret;
    }

    /**
     * 修改资料昵称
     * @param string $account
     * @param string $nickname
     * @return array|mixed|string
     */
    static function modifyNickname($account = '', $nickname = '', $avatar = '')
    {
        if (!$account || !$nickname) return false;
        $ret = (new RongCloud())->userRefresh($account, $nickname, $avatar ?: '1');
        log_info(__CLASS__ . "==modifyNickname=={$account}=={$nickname}==" . json_encode($ret));
        return $ret;
    }

    /**
     * 封禁用户
     * @param string $account
     */
    static function userBlock($account = '', $minutes = 43100)
    {
        if (!$account) return false;
        $ret = (new RongCloud())->userBlock($account, $minutes);
        log_info(__CLASS__ . "==userBlock=={$account}==" . json_encode($ret));
        return $ret;
    }

    /**
     * 解除封禁用户
     * @param string $account
     */
    static function userUnBlock($account = '')
    {
        if (!$account) return false;
        $ret = (new RongCloud())->userUnBlock($account);
        log_info(__CLASS__ . "==userUnBlock=={$account}==" . json_encode($ret));
        return $ret;
    }

    /**
     * 发送静默消息
     * @param string $account
     * @param array $msgInfo
     */
    static function sendSilentMsg($account = '', $msgInfo = [])
    {
        $accounts = !is_array($account) ? [$account] : array_values($account);
        $content = json_encode([
            'name' => 'cmd',
            'data' => $msgInfo,
        ]);
        $sender = config('busi.officialImAccount');
        $isIncludeSender = $isCounted = $isPersisted = 0;
        $accountArr = array_chunk($accounts, self::SINGLE_MAX_NUM);
        $ret = 0;
        foreach ($accountArr as $k => $accounts) {
            try {
                $ret = (new RongCloud())->messagePrivatePublish(
                    $sender,
                    $accounts,
                    self::RONG_CMD_TYPE,
                    $content,
                    $isIncludeSender,
                    $isCounted,
                    $isPersisted
                );
                log_info(__CLASS__ . "==sendSilentMsg==Round:{$k}==" . count($accounts) . "=={$content}==" . json_encode($ret));
            } catch (\Exception $e) {
                log_info(__CLASS__ . "==Exception==" . $e->getMessage());
                continue;
            }
        }
        return $ret;
    }

    /**
     * 添加黑名单
     * @param string $account
     * @param string $black_account
     */
    static function addBlackList($account = '', $black_account = '')
    {
        $ret = (new RongCloud())->userBlacklistAdd($account, [$black_account]);
        log_info(__CLASS__ . "==addBlackList=={$account}=={$black_account}==" . json_encode($ret));
        return $ret;
    }

    /**
     * 删除黑名单
     * @param string $account
     * @param string $black_account
     */
    static function delBlackList($account = '', $black_account = '')
    {
        $ret = (new RongCloud())->userBlacklistRemove($account, [$black_account]);
        log_info(__CLASS__ . "==delBlackList=={$account}=={$black_account}==" . json_encode($ret));
        return $ret;
    }

    /**
     * 官方推送（人工推送，活动、公告这类） - 全员通知（落地）
     */
    static function officialPushToAll(
        $content = [],
        $msgType = self::RONG_TEXT_TYPE,
        $pushContent = '你有一条新消息~'
    ) {
        //发送消息ID
        $fromUserId = ConfigUtil::getOfficialImAccount();
        $ret = (new RongCloud())->messageBroadcast($fromUserId, $msgType, json_encode($content), $pushContent);
        log_info(__CLASS__ . "==officialPushToAll=={$msgType}==" . json_encode($ret) . "==" . json_encode($content));
        return $ret;
    }

    /**
     * 官方推送（人工推送，活动、公告这类） - 指定用户
     */
    static function officialPushToSingle(
        $toUsers = [],
        $content = [],
        $msgType = self::RONG_TEXT_TYPE,
        $pushContent = '你有一条新消息~',
        $officialType = 1
    ) {
        //发送消息ID
        $fromUserId = ConfigUtil::getOfficialImAccount($officialType);
        $toUsers = array_values($toUsers);
        $content['user'] = [
            'id' => ConfigUtil::getOfficialUserId(),
            'name' => '官方消息',
            'portrait' => ConfigUtil::getSystemIcon(),
        ];
        //系统通知
        $ret = (new RongCloud())->messageSystemPublish($fromUserId, $toUsers, $msgType, json_encode($content), $pushContent);

        log_info(__CLASS__ . "==officialPushToSingle=={$msgType}==From:{$fromUserId}==To:" . json_encode($toUsers) . "==" . json_encode($ret) . "==" . json_encode($content));
        return $ret;
    }

    /**
     * 系统消息（日常系统审核结果等一些系统自动的消息推送）
     */
    static function systemPushToSingle(
        $toUsers = [],
        $content = [],
        $msgType = self::RONG_TEXT_TYPE,
        $pushContent = '你有一条新消息~'
    ) {
        //发送消息ID
        $fromUserId = ConfigUtil::getSystemImAccount();
        $content = [
            'content' => $content,
            'extra' => $pushContent,
            'user' => [
                'id' => ConfigUtil::getSystemUserId(),
                'name' => '系统消息',
                'portrait' => ConfigUtil::getSystemIcon(),
            ]
        ];
        $toUsers = array_values($toUsers);
        $ret = (new RongCloud())->messageSystemPublish($fromUserId, $toUsers, $msgType, json_encode($content), $pushContent);
        log_info(__CLASS__ . "==systemPushToSingle=={$msgType}==" . json_encode($toUsers) . "==" . json_encode($ret));
        return $ret;
    }

    /**
     * 获取用户的标签
     */
    static function getUserTags($accounts = [])
    {
        if (empty($accounts)) return [];
        if (!is_array($accounts)) $accounts = [$accounts];
        $accountArr = array_chunk($accounts, self::TAG_GET_MAX_NUM);
        $rongcloud = new RongCloud();
        $ret = [];
        foreach ($accountArr as $round => $ids) {
            $result = $rongcloud->pushUserTagGet($ids);
            $result = json_decode($result, true);
            log_info(__METHOD__ . "==Round:{$round}==RetCode:{$result['code']}==Count:" . count($ids));
            if ($result['code'] != '200') continue;
            $ret = array_merge($ret, $result['result']);
        }
        return $ret;
    }

    /**
     * 设置用户的标签
     */
    static function setUserTags($accounts = [], $tags = [])
    {
        if (empty($accounts)) return [];
        if (!is_array($accounts)) $accounts = [$accounts];
        $accountArr = array_chunk($accounts, self::TAG_SET_MAX_NUM);
        $rongcloud = new RongCloud();
        foreach ($accountArr as $round => $ids) {
            $result = $rongcloud->pushUserTagBatchSet($ids, $tags);
            $result = json_decode($result, true);
            log_info(__METHOD__ . "==Round:{$round}==RetCode:{$result['code']}==Count:" . count($ids));
            if ($result['code'] != '200') return ['round' => $round, 'errcode' => $result['code']];
        }
        return ['errcode' => 0];
    }

    /**
     * 私聊消息撤回
     */
    static function privateMessageRecall($receiver = '', $sender = '', $messageId = '', $sendTime = 0)
    {
        $sender = ConfigUtil::getOfficialImAccount(3);
        $ret = (new RongCloud())->messageRecall($sender, $receiver, $messageId, $sendTime, 1);
        log_info(__METHOD__ . "Sender:{$sender}==Receiver:{$receiver}==MsgId:{$messageId}==SendTime:{$sendTime}");
        return $ret;
    }

    /**
     * 系统消息撤回
     */
    static function sysMessageRecall($receiver = '', $sender = '', $messageId = '', $sendTime = 0)
    {
        $ret = (new RongCloud())->messageRecall($sender, $receiver, $messageId, $sendTime, 6);
        log_info(__METHOD__ . "==Sender:{$sender}==Receiver:{$receiver}==MsgId:{$messageId}==SendTime:{$sendTime}==" . json_encode($ret));
        return $ret;
    }

    /**
     * 融云踢下线
     */
    static function kickOut($userIds = [])
    {
        if (empty($userIds)) return false;
        //兼容非数组
        if (!is_array($userIds)) $userIds = [$userIds];
        $accounts = User::getImAccounts($userIds, -1);
        return (new RongCloud())->userBlock(array_values($accounts), 43200);
    }

    /**
     * 融云取消封禁
     */
    static function cancelKickOut($userIds = [])
    {
        if (empty($userIds)) return false;
        //兼容非数组
        if (!is_array($userIds)) $userIds = [$userIds];
        $accounts = User::getImAccounts($userIds, -1);
        return (new RongCloud())->userUnBlock(array_values($accounts));
    }
}
